//
//  OpenGLUseGLKViewViewController.m
//  CoreAnimation
//
//  Created by 张国文 on 16/10/24.
//  Copyright © 2016年 hangzhouyijiyin. All rights reserved.
//

#import "OpenGLUseGLKViewViewController.h"
#import <GLKit/GLKit.h>

@interface OpenGLUseGLKViewViewController ()

@property (nonatomic, strong) CIContext *ciContext; // coreImage的上下文，此上下文链接EAGLContext(这个是openGL的上下文)，更改此上下文可以及时更改EAGLContext，然后系统应该运用GLKView进行快速渲染图片
@property (nonatomic, strong) GLKView *glkView; // 根据EAGLContext处理大部分的设置和绘制工作，进行图形的展示
@property (nonatomic, strong) CIImage *ciImage; // 图片
@property (nonatomic, strong) CIFilter *openGLESFilter; // 渲染的滤镜

@end

@implementation OpenGLUseGLKViewViewController

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
    self.ciContext = nil;
    [self.glkView removeFromSuperview];
    self.ciImage = nil;
    self.openGLESFilter = nil;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view
    self.view.backgroundColor = [UIColor whiteColor];
    
    /**
     *  本节主要讲运用GLKView进行图片的渲染，这么做可以快速进行图片状态的改变，并且不太浪费内存(经过测试发现在图片改变的时候，会有内存的增加，但是这个过程非常短，对内存的消耗小，我猜测虽然OpenGL对内存的负担小，但是内存仍然需要进行一些计算的操作)，直接和硬件(显卡)进行交互，加快渲染速度。
     */
    
    // 运用GLKView渲染图片的步骤主要有7步：
    // 1、创建OpenGLES渲染的上下文
    EAGLContext *eaglContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
    // 2、创建GLKView
    self.glkView = [[GLKView alloc] initWithFrame:CGRectMake(50, 64 + 50, 250, 150) context:eaglContext];
    [self.view addSubview:_glkView];
    // 3、将EAGLContext和GLKView进行绑定，这样GLKView才能绘制EAGLContext的内容
    [self.glkView bindDrawable];
    // 4、创建CoreImage的上下文，和OpenGLES渲染的上下文进行绑定，运用GPU
    self.ciContext = [CIContext contextWithEAGLContext:eaglContext options:@{kCIContextWorkingColorSpace:[NSNull null]}];
    // 5、创建渲染的滤镜
    self.ciImage = [[CIImage alloc] initWithImage:[UIImage imageWithName:@"filter.jpg"]];
    self.openGLESFilter = [CIFilter filterWithName:@"CISepiaTone"];
    [self.openGLESFilter setDefaults];
    [self.openGLESFilter setValue:self.ciImage forKey:kCIInputImageKey];
    [self.openGLESFilter setValue:@(0.5) forKey:kCIInputIntensityKey];
    NSLog(@"滤镜的结构：%@", self.openGLESFilter.attributes); // 我们如果对滤镜怎么进行赋值不懂得话，可以打印attributes属性，这里面有该滤镜所有的属性的含义。
    // 6、CoreImage的上下文从经过滤镜过滤过的图片上提取结果并将结果转化为OpenGLES上下文上面，这一步相当于运用cpu
    [self.ciContext drawImage:[self.openGLESFilter outputImage] inRect:CGRectMake(0, 0, self.glkView.drawableWidth, self.glkView.drawableHeight) fromRect:[self.ciImage extent]];
    // 7、运用GLKView及时对OpenGLES的上下文进行渲染绘制
    [self.glkView display];

#warning 警告
    // ok现在运用GLKView进行图片渲染已经完成了，你可能不知道这样有什么用，感觉不出来GLKView渲染图片的优势，现在让我们添加一个UISlider，实时的改变滤镜的效果，看看我们的GLKView性能的表现状况。
    
    UISlider *slider = [[UISlider alloc] initWithFrame:CGRectMake(0, 400, [UIScreen mainScreen].bounds.size.width, 30)];
    slider.minimumValue = 0.0f;
    slider.maximumValue = 1.0f; // 我为什么这样设置最大值和最小值呢？原因是因为滤镜的kCIInputIntensityKey的取值范围为0~1
    [slider setValue:0.5];
    [slider addTarget:self action:@selector(changeFilterValue:) forControlEvents:UIControlEventValueChanged];
    [self.view addSubview:slider];
    
#warning 警告
    // ok经过滑动slider，给滤镜不同的值，你是不是发现没有造成卡顿呢，这就是OpenGLES的优势所在，因为OpenGLES很少消耗内存，是和硬件直接进行交互的。
    
}

- (void)changeFilterValue:(UISlider *)slider
{
    // 1、进行上下文的重新绑定 2、这里我们只需要改变滤镜的值，3、并且重新运用coreImage上线文对图片进行上下文转换，4、最后运用GLKView绘制出来就好了
    // 1
      [self.glkView bindDrawable]; // 这句话最好不要省略，这句话的意思是在上下文的内容进行改变的时候，你都需要手动进行绑定操作，在你移动slider的时候上下文的内容就改变了，如果不加的话不会出错但是在你移动slider的时候会出现短暂的黑屏，这是因为在你移动slider的时候上下文的内容已经改变。
    // 2
    [self.openGLESFilter setValue:@(slider.value) forKey:kCIInputIntensityKey];
    // 3
     [self.ciContext drawImage:[self.openGLESFilter outputImage] inRect:CGRectMake(0, 0, self.glkView.drawableWidth, self.glkView.drawableHeight) fromRect:[self.ciImage extent]];
    
    // 4
    [self.glkView display];
}


@end
